#ifndef DEF_HEADER
#define DEF_HEADER

#include<string>
#include<fstream>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<map>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<random>
#include "singleton.hpp" /// for singleton class

using namespace std;

namespace Puza{
  /* Main Definitions */
  enum ModelType{
    MODEL_GENERATOR,
    MODEL_ESTIMATOR,
    MODEL_TOPICMODEL,
    MODEL_ERROR
  };
  
  enum EstimatorType{
    EST_POLYA,
    EST_ERROR
  };
  
  enum GeneratorType{
    GE_MULTINOMIAL,
    GE_DIRICHLET,
    GE_POLYA,
    GE_ERROR
  };
  
  enum InputType{
    INPUT_TEXT,
    INPUT_BUFFER_PROTOCOL, 
    INPUT_ERROR
  };
  
  enum OutputType{
    OUTPUT_TEXT,
    OUTPUT_BUFFER_PROTOCOL,
    OUTPUT_ERROR
  };
  
  enum TopicModelType{
    TOPICMODEL_LDA_GIBBS_SAMPLING,
    TOPICMODEL_LDA_VARIATIONAL_BAYES,
    TOPICMODEL_LDA_VARIATIONAL_BAYES_ONLINE,
    TOPICMODEL_ERROR
  };
  
  enum TopicModelTaskType{
    TOPICMODEL_TASK_INFERENCE,
    TOPICMODEL_TASK_PREDICTION,
    TOPICMODEL_TASK_INFERENCE_AND_PREDICTION,
    TOPICMODEL_TASK_INTERACTIVE,
    TOPICMODEL_TASK_ERROR
  };

  typedef struct TermItemStruct{
    int term_id;
    int term_stat;
  }TermItem;
  
  enum PolyaEstimatorType{
    EST_POLYA_SGD,
    EST_POLYA_NEWTON,
    EST_POLYA_FIXEDPOINT,
    EST_POLYA_ERROR
  };

  enum GeoValueType{
    GEO_TYPE_DISCRETE,
    GEO_TYPE_REAL
  };

  typedef vector<TermItem> TermList;
  typedef vector<TermList> DocList;
  
  typedef int(*ModelFunc)();
  typedef map<int,string> IdMapping;
  typedef map<int,double> TimeMapping;
  typedef map<int,double> GeoTermItem;
  typedef vector<GeoTermItem> GeoTerms;

  
  class DEF{
  public:
    /* Global Variables */
    ModelType currentModelType;
    string input_file_name;
    string train_file_name;
    string test_file_name;
    string output_file_name;
    ifstream InputFile;
    ofstream LogFile;
    InputType currentInputType;
    OutputType currentOutputType;
    IdMapping data_ids;
    TimeMapping data_timestamps;
    
    /* Topic Model Variables */
    TopicModelType currentTopicModelType;
    TopicModelTaskType currentTopicModelTaskType;
    int** TM_Doc;
    int DOC_NUM;
    int TOPIC_NUM;
    int TERM_NUM;
    int AUTHOR_NUM;
    double* LDA_alpha;
    double* LDA_beta;
    double LDA_initial_alpha;
    double LDA_initial_beta;
    int BatchSize;
    double LDA_VBONLINE_tau0;
    double LDA_VBONLINE_kappa;
    int GEO_REGION_NUM;
    int GEO_USER_NUM;
    double GEO_LEARNING_RATE;
    double GEO_REG;
    int GEO_REG_TYPE;
    int GEO_REG_L1_K;
    double GEO_REG_L1_G;
    GeoValueType GEO_TYPE;
    int GEO_M_ITER;
    int GEO_E_ITER;
    
    /* Estimator Variables */
    EstimatorType currentEstimatorType;
    PolyaEstimatorType currentPolyaEstimatorType;
    int** EST_BUFFER_INT;
    double** EST_BUFFER_DOUBLE;
    int EST_Samples;
    int EST_Polya_K;
    double EST_Polya_SGD_Initial_Rate;
    
    /* Generator Variables */
    GeneratorType currentGeneratorType;
    int GE_Samples;
    
    int GE_Multinomial_K;
    int GE_Multinomial_N;
    double* GE_Multinomial_P;
    unsigned int* GE_Multinomial_Data;
    
    int GE_Dirichlet_K;
    double GE_Dirichlet_Alpha;
    double* GE_Dirichlet_Base;
    double* GE_Dirichlet_Data;
    
    int GE_Polya_K;
    int GE_Polya_N;
    double GE_Polya_Alpha;
    double* GE_Polya_Base;
    unsigned int* GE_Polya_Data;
    
    mt19937 random_eng;
    
    DEF();
  };

  /* singleton definitions */
  typedef Singleton<DEF> PuzaDEF; 

};
#endif
